﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Windows.Media.Imaging;
using AndroidSigner.Utils;
using ApkNet.ApkReader;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.Win32;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using ZipFile = System.IO.Compression.ZipFile;

namespace AndroidSigner.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        #region VM

        private string _selectedApkPath = string.Empty;

        public string SelectedApkPath
        {
            get => _selectedApkPath;
            set
            {
                _selectedApkPath = value;
                RaisePropertyChanged();
            }
        }

        private string _keyFilePath = string.Empty;

        public string KeyFilePath
        {
            get => _keyFilePath;
            set
            {
                _keyFilePath = value;
                RaisePropertyChanged();
            }
        }

        private string _keyAlias = string.Empty;

        public string KeyAlias
        {
            get => _keyAlias;
            set
            {
                _keyAlias = value;
                RaisePropertyChanged();
            }
        }

        private string _keyPassword = string.Empty;

        public string KeyPassword
        {
            get => _keyPassword;
            set
            {
                _keyPassword = value;
                RaisePropertyChanged();
            }
        }

        private ObservableCollection<string> _driveCollection = new ObservableCollection<string>();

        public ObservableCollection<string> DriveCollection
        {
            get => _driveCollection;
            set
            {
                _driveCollection = value;
                RaisePropertyChanged();
            }
        }

        private BitmapImage _apkIcon = new BitmapImage(new Uri(@"..\..\Images\android.png", UriKind.Relative));

        public BitmapImage ApkIcon
        {
            get => _apkIcon;
            set
            {
                _apkIcon = value;
                RaisePropertyChanged();
            }
        }

        private string _apkName = string.Empty;

        public string ApkName
        {
            get => _apkName;
            set
            {
                _apkName = value;
                RaisePropertyChanged();
            }
        }

        private string _packageName = string.Empty;

        public string PackageName
        {
            get => _packageName;
            set
            {
                _packageName = value;
                RaisePropertyChanged();
            }
        }

        private string _versionCode = string.Empty;

        public string VersionCode
        {
            get => _versionCode;
            set
            {
                _versionCode = value;
                RaisePropertyChanged();
            }
        }

        private string _versionName = string.Empty;

        public string VersionName
        {
            get => _versionName;
            set
            {
                _versionName = value;
                RaisePropertyChanged();
            }
        }

        private string _outputLog = string.Empty;

        public string OutputLog
        {
            get => _outputLog;
            set
            {
                _outputLog = value;
                RaisePropertyChanged();
            }
        }

        #endregion

        #region DelegateCommand

        public DelegateCommand SelectedApkCommand { set; get; }
        public DelegateCommand CreateKeyCommand { set; get; }
        public DelegateCommand SelectKeyCommand { set; get; }
        public DelegateCommand ShowSha1Command { set; get; }
        public DelegateCommand StartSignCommand { set; get; }

        #endregion

        private string _destinationDirectory = string.Empty;
        private readonly BackgroundWorker _backgroundWorker;

        public MainWindowViewModel(IDialogService dialogService)
        {
            _backgroundWorker = new BackgroundWorker();
            _backgroundWorker.WorkerReportsProgress = true;
            _backgroundWorker.WorkerSupportsCancellation = true;
            _backgroundWorker.DoWork += Worker_OnDoWork;
            _backgroundWorker.ProgressChanged += Worker_OnProgressChanged;
            _backgroundWorker.RunWorkerCompleted += Worker_OnRunWorkerCompleted;

            SelectedApkCommand = new DelegateCommand(delegate
            {
                var fileDialog = new OpenFileDialog
                {
                    // 设置默认格式
                    DefaultExt = ".apk",
                    Filter = "安装包文件(*.apk)|*.apk"
                };
                var result = fileDialog.ShowDialog();
                if (result != true) return;
                SelectedApkPath = fileDialog.FileName;
                ApkName = fileDialog.SafeFileName;

                //解压缩
                if (_backgroundWorker.IsBusy)
                {
                    dialogService.ShowDialog(
                        "AlertMessageDialog",
                        new DialogParameters
                        {
                            { "AlertType", AlertType.Error }, { "Title", "温馨提示" }, { "Message", "当前正在处理文件中" }
                        },
                        delegate { }
                    );
                    return;
                }

                _backgroundWorker.RunWorkerAsync();
            });

            CreateKeyCommand = new DelegateCommand(delegate
            {
                dialogService.ShowDialog(
                    "CreateKeyDialog", new DialogParameters { { "Title", "新建签名证书" } }, delegate(IDialogResult result)
                    {
                        KeyFilePath = result.Parameters.GetValue<string>("KeySavePath");
                        KeyAlias = result.Parameters.GetValue<string>("KeyAlias");
                        KeyPassword = result.Parameters.GetValue<string>("KeyPassword");
                    }
                );
            });
            SelectKeyCommand = new DelegateCommand(delegate
            {
                var fileDialog = new OpenFileDialog
                {
                    // 设置默认格式
                    DefaultExt = ".jks",
                    Filter = "秘钥文件(*.jks)|*.jks"
                };
                var result = fileDialog.ShowDialog();
                if (result == true)
                {
                    KeyFilePath = fileDialog.FileName;
                }
            });
            ShowSha1Command = new DelegateCommand(delegate
            {
                if (string.IsNullOrWhiteSpace(_keyFilePath) || string.IsNullOrWhiteSpace(_keyAlias) ||
                    string.IsNullOrWhiteSpace(_keyPassword))
                {
                    dialogService.ShowDialog(
                        "AlertMessageDialog",
                        new DialogParameters
                        {
                            { "AlertType", AlertType.Error }, { "Title", "温馨提示" }, { "Message", "请完善签名配置" }
                        },
                        delegate { }
                    );
                    return;
                }

                if (!string.IsNullOrEmpty(OutputLog))
                {
                    OutputLog = string.Empty;
                }

                var cmd = $"-v -list -alias {_keyAlias} -keystore {_keyFilePath} -storepass {_keyPassword}";
                CommandHub.Get.ExecuteCommand("keytool ", cmd, value => OutputLog = value);
            });
            StartSignCommand = new DelegateCommand(delegate
            {
                if (string.IsNullOrWhiteSpace(_selectedApkPath) || string.IsNullOrWhiteSpace(_keyFilePath) ||
                    string.IsNullOrWhiteSpace(_keyAlias) || string.IsNullOrWhiteSpace(_keyPassword))
                {
                    dialogService.ShowDialog(
                        "AlertMessageDialog",
                        new DialogParameters
                        {
                            { "AlertType", AlertType.Error }, { "Title", "温馨提示" }, { "Message", "请完善签名配置" }
                        },
                        delegate { }
                    );
                    return;
                }

                var outputFilePath = $@"{FilePathHub.Get.GetDesktopPath()}\{ApkName.DeleteSuffix()}.signed.apk";

                if (!string.IsNullOrEmpty(OutputLog))
                {
                    OutputLog = string.Empty;
                }

                //apk签名
                var cmd = "sign -verbose " +
                          $"--ks {_keyFilePath} " +
                          "--v1-signing-enabled false " +
                          "--v2-signing-enabled true " +
                          $"--ks-key-alias {_keyAlias} " +
                          $"--ks-pass pass:{_keyPassword} " +
                          $"--key-pass pass:{_keyPassword} " +
                          $"--out {outputFilePath} " +
                          $"{_selectedApkPath}";
                CommandHub.Get.ExecuteCommand($@"{AppDomain.CurrentDomain.BaseDirectory}apksigner.bat ", cmd,
                    value => OutputLog = value);
            });
        }

        private void Worker_OnDoWork(object sender, DoWorkEventArgs e)
        {
            _destinationDirectory = $"{FilePathHub.Get.GetDesktopPath()}\\Temp";
            ZipFile.ExtractToDirectory(SelectedApkPath, _destinationDirectory);
        }

        private void Worker_OnProgressChanged(object sender, ProgressChangedEventArgs e)
        {
        }

        private void Worker_OnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //解析APK文件
            ExtractApkResources();
        }

        /// <summary>
        /// 从APK里面提取资源
        /// </summary>
        private void ExtractApkResources()
        {
            byte[] manifestData = null;
            byte[] resourcesData = null;
            using (var zip = new ZipInputStream(File.OpenRead(_selectedApkPath)))
            {
                using (var filestream = new FileStream(_selectedApkPath, FileMode.Open, FileAccess.Read))
                {
                    var zipFile = new ICSharpCode.SharpZipLib.Zip.ZipFile(filestream);
                    ZipEntry zipEntry;
                    while ((zipEntry = zip.GetNextEntry()) != null)
                    {
                        if (zipEntry.Name.ToLower() == "androidmanifest.xml")
                        {
                            manifestData = new byte[50 * 1024];
                            using (var stream = zipFile.GetInputStream(zipEntry))
                            {
                                stream.Read(manifestData, 0, manifestData.Length);
                            }
                        }

                        if (zipEntry.Name.ToLower() == "resources.arsc")
                        {
                            using (var stream = zipFile.GetInputStream(zipEntry))
                            {
                                using (var s = new BinaryReader(stream))
                                {
                                    resourcesData = s.ReadBytes((int)zipEntry.Size);
                                }
                            }
                        }
                    }
                }
            }

            var apkReader = new ApkReader();
            try
            {
                var info = apkReader.extractInfo(manifestData, resourcesData);

                if (info.iconFileName.Count > 0)
                {
                    var last = info.iconFileName.FindLast(icon => icon.EndsWith("png"));
                    var iconPath = $"{_destinationDirectory}\\{last.Replace("/", "\\")}";
                    ApkIcon = iconPath.FileToBitmapImage();
                }
                else
                {
                    ApkIcon = new BitmapImage(new Uri(@"..\..\Images\android.png", UriKind.Relative));
                }

                PackageName = info.packageName;
                VersionCode = info.versionCode;
                VersionName = info.versionName;
            }
            catch (Exception)
            {
                PackageName = "解析失败";
                VersionCode = "解析失败";
                VersionName = "解析失败";
            }
        }
    }
}